package com.zy.is.common.shiro;

import cn.hutool.core.codec.Base64;
import com.zy.is.common.utils.SignUtil;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @ClassName: ShiroConfig
 * @Description: shiro配置类
 * @Author: Yanzy
 * @Data: 2021/4/2 15:44
 * @Source: 1.0
 */
@Configuration
public class ShiroConfig {


    /**
     * 自定义密码验证器
     *
     * @return
     */
    @Bean(value = "credentialsMatcher")
    public CredentialsMatcher credentialsMatcher() {
        // 自定义验证器
        //return new MyShiroMatcher();
        // shiro自带加密密码验证器
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 加密方式【MD5加密方式 目前无法反解密，属于安全加密】
        hashedCredentialsMatcher.setHashAlgorithmName(SignUtil.MD5);
        // 加密迭代次数
        hashedCredentialsMatcher.setHashIterations(SignUtil.SIGN_TIMES);
        return hashedCredentialsMatcher;
    }

    /**
     * 自定义登录验证器
     *
     * @param credentialsMatcher
     * @return
     */
    @Bean
    public MyShiroRealm myShiroRealm(@Qualifier("credentialsMatcher") CredentialsMatcher credentialsMatcher) {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setCredentialsMatcher(credentialsMatcher);
        // 启用缓存
        myShiroRealm.setCachingEnabled(true);
        // 设置认证缓存
        myShiroRealm.setAuthenticationCachingEnabled(true);
        myShiroRealm.setAuthenticationCacheName("authenticationCache");
        // 设置授权缓存
        myShiroRealm.setAuthorizationCachingEnabled(true);
        myShiroRealm.setAuthorizationCacheName("authorizationCache");
        return myShiroRealm;
    }

    /**
     * ehcache缓存
     *
     * @return
     */
    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManagerConfigFile("classpath:config/ehcache.xml");
        return ehCacheManager;
    }

    /**
     * 记住密码cookie
     * @return rememberedMeCookie
     */
    @Bean
    public SimpleCookie rememberedMeCookie() {

        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        simpleCookie.setHttpOnly(true);
        // 记住时间 (单位: 秒)
        simpleCookie.setMaxAge(60 * 60 * 24);
        return simpleCookie;
    }

    /**
     * RememberMe管理器
     * @return cookieRememberMe
     */
    @Bean
    public CookieRememberMeManager cookieRememberMe() {

        CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
        rememberMeManager.setCookie(rememberedMeCookie());
        rememberMeManager.setCipherKey(Base64.decode("zy-is-shiro"));
        return rememberMeManager;
    }


    @Bean(name="webSessionManager")
    public DefaultWebSessionManager webSessionManager(){
        DefaultWebSessionManager webSessionManager = new DefaultWebSessionManager();
        webSessionManager.setSessionIdUrlRewritingEnabled(false);
        return webSessionManager;
    }

    /**
     * 自定义安全管理策略
     */
    @Bean
    public SecurityManager securityManager(MyShiroRealm myShiroRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置自定义的realm
        securityManager.setRealm(myShiroRealm);
        // 设置自定义缓存
        securityManager.setCacheManager(ehCacheManager());
        // 设置remember
        securityManager.setRememberMeManager(cookieRememberMe());
        // 设置session
        securityManager.setSessionManager(webSessionManager());
        return securityManager;
    }

    /**
     * 地址过滤器
     *
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 设置安全管理
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 设置登录地址
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 设置主页地址
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 设置未授权的url
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 开放登录接口
        filterChainDefinitionMap.put("/doLogin", "anon");
        // 生成验证码接口
        filterChainDefinitionMap.put("/captcha/captchaImg", "anon");
        // 开放静态资源文件
        filterChainDefinitionMap.put("/assets/**", "anon");
        // 其余url全部拦截，必须放在最后
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * shiro生命周期
     * @return
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * shiro注解启用配置
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        sourceAdvisor.setSecurityManager(securityManager);
        return sourceAdvisor;
    }
}
